# Integratsiooninõuded tarkvaralahendustele

Integratsiooniliste otsuste, protokollide valiku ja sõnumivahetuse põhimõtted SMIT majutusplatvormil. Määratleb kuidas komponendid peaksid omavahel suhtlema ja andmeid vahetama.

Need nõuded määratlevad kuidas peaksid tarkvara komponendid omavahel suhtlema, milliseid protokolle kasutada ja kuidas tagada turvaline ja usaldusväärne andmevahetus.

Need nõuded vajavad inimeste järelevalvet, arhitektuurilisi otsuseid ja protsessijuhtimist ning ei ole automaatselt jõustatavad arendusprotsessis.

**Täiendavad dokumendid**:

- Automaatselt jõustatavate tehniliste standardite jaoks vaata [rules/common/component-technical-standards.mdc](https://source.smit.sise/projects/IDP/repos/smit-development-standards/browse/rules/common/component-technical-standards.mdc)
- Automatiseeritavate integratsioonimustrite jaoks vaata [rules/common/integration-standards.mdc](https://source.smit.sise/projects/IDP/repos/smit-development-standards/browse/rules/common/integration-standards.mdc)

## Sünkroonne ja asünkroonne suhtlusviis

Rakendused saavad omavahel suhelda sünkroonselt või asünkroonselt:

### Sünkroonne suhtlemine

Teenuskutse tegija ootab seni kuni teenusepakkuja poolt on vastus saadaval. Samaaegselt võib toimuda üks toiming:

- Üks laialdasemalt kasutatud suhtlusstiile
- Kontseptuaalne lihtsus võimaldab hõlpsalt rakendada
- Enamikes olukordades sobiv suhtlusstiil
- Tihedalt seotud HTTP protokolliga, kuid on ka teisi protokolle, nt RPC

```mermaid
---
title: Sünkroonne suhtlemine
---
sequenceDiagram
    participant Client as Klient
    participant API as API Teenus
    participant DB as Andmebaas

    Client ->> API: HTTP Request
    Note over Client, API: Klient ootab vastust
    API ->> DB: Andmepäring
    DB -->> API: Andmed
    API -->> Client: HTTP Response
    Note over Client: Klient saab vastuse
```

**Sünkroonse integratsiooni puhul on eelistatud:**

- Protokolliks HTTP ning andmeformaadiks JSON
- SOAP/XML lahendusi kasutada ainult olemasolevate süsteemidega liidestamisel, kus muid võimalusi ei ole
- Kasutada saab nii X-tee integratsiooni kui ka otse tehtavaid HTTP teenuseid
- Kõige levinum stiil HTTP teenuse loomisel on REST, kuid on võimalus ka kasutada GraphQL-i (ainult läbi eelneva kooskõlastuse)

### Asünkroonne suhtlemine

Teenuskutse tegija ei oota teenusepakkuja poolt vastust. Samaaegselt võib toimuda mitu toimingut:

- Sobib hästi hajussüsteemi, -arhitektuuri jaoks
- Teenused ei ole omavahel seotud, sest suhtlemiseks kasutatakse sõnumisiini, mis võimaldab rakenduste vahel sõnumeid vahetada

```mermaid
---
title: Asünkroonne suhtlemine
---
sequenceDiagram
    participant Producer as Tootja
    participant Queue as Sõnumijärjekord
    participant Consumer as Tarbija

    Producer ->> Queue: Sõnum
    Note over Producer: Ei oota vastust
    Producer ->> Queue: Teine sõnum
    Note over Producer: Võib jätkata tööd

    Queue ->> Consumer: Sõnum
    Consumer ->> Consumer: Töötleb sõnumi
    Note over Consumer: Võib kaua aega võtta
    Consumer ->> Queue: Kinnitus
```

**Asünkroonse integratsiooni puhul on eelistatud:**

- Andmevahetusformaadiks tekstiliste andmete puhul samuti JSON
- Andmevahetuseprotokollina AMQP protokolli

*Allikas: Gupta, P. (05.06.2018). Patterns for Microservices – Sync vs. Async. DZone. <https://dzone.com/articles/patterns-for-microservices-sync-vs-async>*

## Integratsioon süsteemide vahel (nii välised kui sisemised)

Rakendusi omavahel integreerides peame peamiselt arvestama kolme aspekti:

1. Kas kaks omavahel liidestavat komponenti on määratletud sama andmekogu alla
2. Kas toimub andmekogu sisene integratsioon või andmekogu ülene integratsioon  
3. Kas üks liidestavatest komponentidest asub välisperimeetris/õues (taotluskeskkonnad)

**Andmekogu** on see süsteem, mis on määrusega registreeritud. Kui on segadus, konsulteeri oma tooteomanikuga.

```mermaid
---
title: Integratsioon süsteemide vahel
---
graph TB
    subgraph External["🌐 Välisperimeeter"]
        ExtApp["📱 Väline Rakendus"]
    end

    subgraph Internal["🏗️ Sisemine Võrk"]
        subgraph AndmA["📊 Andmekogu A"]
            SystemA1["🧩 Süsteem A1"]
            SystemA2["🧩 Süsteem A2"]
        end
        subgraph AndmB["📊 Andmekogu B"]
            SystemB1["🧩 Süsteem B1"]
            SystemB2["🧩 Süsteem B2"]
        end
        XTee["🔗 X-TEE Gateway"]
        Adapter["🔧 Vaheadapter"]
    end

    ExtApp --> Adapter
    Adapter --> SystemA1
    Adapter --> SystemB1

    SystemA1 -.->|Andmekogusisene| SystemA2
    SystemB1 -.->|Andmekogusisene| SystemB2

    SystemA1 --> XTee
    SystemB1 --> XTee
    XTee --> SystemB1
    XTee --> SystemA1
```

### Integratsioonireeglid

| Tüüp | Reegel | Märkused |
|------|--------|----------|
| **Andmekogusisene integratsioon** | Võib teha nii sünkroonselt kui asünkroonselt ning ei pea kasutama X-TEEd | Liidestus lahendusega, mis ei kuulu ühegi andmekogu alla |
| **Andmekogude vaheline integratsioon** | Tohib teha ainult üle X-TEE ning tulenevalt X-TEE piirangutest, siis täna ainult sünkroonselt | Lähtuda tuleb X-TEE dokumentatsioonist |
| **Välisperimeetri komponendid** | Ei ole lubatud otse liidestuda sisemiste süsteemidega sh. X-TEE-ga | Neil tuleb sisevõrku teha vaheadapter, mis päringud edastab |
| **Andmekogu pärib väliselt** | Võib teha ilma X-TEEd kasutamata | Kui andmekogu soovib andmeid pärida lahenduselt, mis ei kuulu andmekogusse |
| **Sisemine süsteem pärib andmekogust** | Tuleb kasutada X-TEEd | Kui sisemine süsteem pärib andmekogu käest andmeid |

**Välist rakendust disainides** tuleks pöörata tähelepanu, et selle mõju sisemistele komponentidele oleks minimaalne (turva, käideldavus, terviklikkus). Eriti arvesse võtta olukordi, kus väline rakendus võib rünnaku alla sattuda.

## Sõnumivahetuse nõuded (MQ)

### Sõnumivahetuse mudelid

Lubatud on kasutada vastavalt vajadusele nii **publish/subscribe** (queue - järjekorrad), kui **point-2-point** (topic - teemad) mudelit.

### Sõnumid

| Nõue | Kirjeldus |
|------|-----------|
| **JSON sõnumid** | Kõik sõnumid peavad olema JSON formaadis, välja arvatud binaarfailide edastamine |
| **JSON schema valideerimine** | Kõik JSON sõnumid tuleb valideerida kasutades json-schema validaatorit |
| **Binaarfailide edastamine** | Binaarkujul failide edastamiseks läbi sõnumite tuleb kasutada JSON sõnumit, ning faili sisu lisada Base64 kodeeritud kujul |
| **Korrelatsiooni ID** | Küsimus-vastus (request-response) tüüpi sõnumivahetuses tuleb küsimuse vastust identifitseerida korrelatsiooni identifikaatoriga (correlation-id) |

### Sõnumiserveri kanalid

| Nõue | Kirjeldus |
|------|-----------|
| **Kanalite kooskõlastamine** | Juhul kui kanalite nimetused ning nende sisu ei ole eelnevalt kokku lepitud, tuleb kasutatavate kanalite arv ning nimetused kooskõlastada SMIT-iga |
| **JSON schema dokumentatsioon** | Kõik sõnumite sisu tuleb defineerida JSON schema failides ja dokumenteerida AsyncAPI spetsifikatsioonis |

### Sõnumi edastamine

**Kanalite nimetuste nimekonventsioonina** järgida üldjoontes malli: `"[andmete omanik].[sõnumis olevad andmed]"`

Näiteks: `"amr.ametijuhend"`

#### Nimekonventsioonid erinevatele sõnumitüüpidele

| Sõnumitüüp | Suffiks | Näide |
|------------|---------|-------|
| **Küsimus-vastus (request-response)** | Request/Response | `"amr.ametijuhendRequest"` ja `"amr.ametijuhendResponse"` |
| **Ühelt-mitmele (topic)** | Topic | `"amr.ametijuhendTopic"` |
| **Ühelt-ühele, ilma vastust ootamata (queue)** | Queue | `"amr.ametijuhendQueue"` |

### Ühenduskiht

Juhul kui ei ole määratud teisiti, käib suhtlus sõnumiserveriga TCP tasemel (vm tase oleks kiire aga mõistlik on sõnumiserver hoida rakendusest väljaspool, et tagada käideldavus).

**Kohustuslik kasutada AsyncAPI spetsifikatsiooni** (<https://www.asyncapi.com/en>) andmevahetuse dokumenteerimiseks.

## REST API ja HTTP/JSON API rakenduste teenuste arendamise nõuded

### Kontekst

REST on arhiekturistiil, mis kirjeldab nõuded/piirangud rakenduste loomiseks, võttes aluseks veebiarhitektuuri (world-wide-web ehk www).

REST puhul on peamine informatsiooni abstraktsioon **ressurss** (ingl resource). Mistahes teave, mida saab nimetada, võib olla ressurss. (Fielding, 2000)

Ressurss varieerub ajas ning tähistab konkreetsel ajahetkel olemite kogumit või väärtusi (Fielding, 2000).

*Allikas: Fielding, R. T. (2000). Architectural Styles and the Design of Network-based Software Architectures. University of California, Irvine. <https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm>*

### Üldised nõuded API-le

| Nõue | Kirjeldus |
|------|-----------|
| **API dokumentatsioon** | API-del peaks olema loodud dokumentatsioon, mis sisaldab detailset api kirjeldust. Soovituslik on läheneda API-FIRST, ehk api kirjeldatakse ära ja siis luuakse implementatsioon |
| **OpenAPI spetsifikatsioon** | Kõik REST API-d peavad olema dokumenteeritud OpenAPI (Swagger) spetsifikatsioonis. OpenAPI fail peab olema kättesaadav ja ajakohane |
| **"Contract-First" lähenemine** | API leping tuleb defineerida enne implementatsiooni. OpenAPI spetsifikatsioon peab olema esimene dokument, mis luuakse |
| **Schema kirjeldused** | API-i juures kasutatavatel andmekomplektidel (eeldatavasti siis JSON dokumendid) peaksid eksisteerima "schema" kirjeldused. Soovituslik on see teha API enda kirjelduse juures |
| **Valideerimisloogika** | Schemad on vajalikud nii kommunikeerimisel teiste osapooltega, kes API-t kasutavad, kui ka võimaldab luua paremini valideerimisloogikat lähtekoodis |

### Ressurside URL-i kujud

| URL muster | Kirjeldus | Näide |
|------------|-----------|-------|
| `/X` | Tagastab ressursi X massiivi | `/persons` |
| `/X/{id}` | Tagastab konkreetse X ressursi id järgi | `/persons/1` |
| `/X/Y` | Tagastab X listi, mida on filtreeritud Y järgi | `/persons/applications` |
| `/X/{id}/Y` | Tagastab ressursi Y listi, mis on X id-ga seotud | `/persons/1/applications` |
| `/X/Y/{id}` | Tagastab X ressursi listi, mida on filtreeritud Y id järgi | `/applications/persons/1` |

### Ressursside nimetamine

- Lihtsad ja arusaadavad ressursid vastavalt äriloogikale ja seostele
- Ressursi nimetus mitmuses väljendab, et ressurss on mitmuses
- Ressursside nimetamisel ei kasutata käske (nt `/getPersons` või `/createPerson` ei ole õige)
- Ressursside nimetamise asemel väljendavad HTTP käsud/meetodid ressurssidega tehtavaid toiminguid
- Ressursid (sh. parameetrid), mis koosnevad mitmest sõnast tuleb kokku liita sidekriipsuga (-)

### Toimingud ressurssidega

Ressursidega toiminguteks tuleb kasutada HTTP käske. Näiteks `/persons` puhul:

| HTTP meetod | Toiming | Kirjeldus |
|-------------|---------|-----------|
| `GET /persons` | Tagastab massiivi kõikidest isikutest | - |
| `POST /persons` | Loob uue isiku | - |
| `DELETE /persons` | Kustutab olemasolevad isikud ja nende seosed | Sõltub ärivajadusest, kas tegemist on loogilise või füüsilise kustutamisega |
| `PUT /persons` | Asendab kõik olemasolevad kirjed PUT teenuskutse sisendiga täies mahus | - |
| `PATCH /persons` | Asendab kõikidel olemasolevatel kirjetel PATCH teenuskutse sisendiga antud konkreetsete väljade väärtused | - |

### Otsingu tugi API ressurssides

- Kui tahta sorteerida, filtreerida, otsida, siis kasutada query parameetrit ehk päringu keerukus viia '?' taha
- Näide: `GET /persons?name=X&age=Y`
- Kui API võib tagastada pikki nimekirju, siis tuleb kindlasti kasutada osade kaupa küsimist (ingl pagination/paging)
- Näide: `/persons?limit=25&offset=50` (vaikimisi limit=10 ja offset=0)

### API ressursside/teenuste versioneerimine

| Nõue | Kirjeldus |
|------|-----------|
| **Tagasiühilduvus** | Iga kasutuses oleva API muudatus peab olema tagasiühilduv |
| **Uue versiooni loomine** | Uus versioon tuleb luua nt kui muudetakse API sisendi/väljundi struktuuri; eemaldatakse mõni väli |
| **Vanade versioonide tugi** | Uue versiooni loomisel peab eelmine versioon toetatud olema |
| **Versioonide eemaldamine** | Vanade versioonide eemaldamine eeldab tarbijatega kokkulepet ja vastavat protsessi/reeglistikku |

**Versiooninimes kasutada** v eesliidet ning väikeste versioonide asemel kasutada suuri versiooni numbreid, nt v1, v2, v3

**Versiooninumber tuleb hoida URL-i sees kõige vasakul pool**: `/v1/persons`

*Märkus: Kõige lihtsam versioonimine, aga ei ole REST arhitektuuristiiliga kooskõlas*

### API veahaldus

API rakenduses peab olema lahendatud, kuidas vigu hallatakse ning neid tarbijatele väljastatakse.

**Luua korrektne veahaldus HTTP koodide põhiselt:**

| HTTP kood | Kirjeldus |
|-----------|-----------|
| 200 | OK |
| 400 | Bad Request from client |
| 500 | Internal Server Error |
| 304 | Not Modified |
| 404 | Not Found |
| 401 | Unauthorized |
| 403 | Forbidden |

**Lisaks veakoodile lisada ka detailsem veateade:**

```json
{
  "status": "401", 
  "message": "Authentication Required",
  "code": 20003
}
```

### API rakenduse kättesaadavus

Kogu rakenduse API võiks kättesaadav olla eraldi domeeninime või kausta alt.

Näiteks: `api.rakendus.smit` või `rakendus.smit/api/`

### Tuvastamine

Tuvastamist või isikustatud päringute tegemisel, peab identifitseerimist määratleb token (JWT) või vastav räsi minema HTTP päringu päisesse (headers).

## SOAP teenuste arendamise nõuded

### Üldised nõuded

- Liidesed luuakse **"Contract-First"** põhimõttel kasutades SOAP Document Literal sõnumivahetuse põhimõtet
- XSD-sse peab saama sisse viia uuendusi, ilma et olemasolevate kasutamine oleks häiritud

### Nõuded XML schemale

**Complex Type definitsioonid:**

- Tohivad sisaldada ainult sequence tüüpi model group komponenti kordsustega `minOccurs="1"` ja `maxOccurs="1"`
- Ei tohi sisaldada atribuutide deklaratsioone
- Liik (variety) peab olema element-only

**Sequence peab koosnema kas:**

1. Ühest element deklaratsioonist kordsustega `minOccurs="0"` ja `maxOccurs="unbounded"`
2. Nullist või rohkemast element deklaratsioonist minimaalse kordsusega `minOccurs="0"` või `minOccurs="1"`, maksimaalse kordusega `maxOccurs="1"` ning lõppema any deklaratsiooniga atribuutidega `processContents="lax" minOccurs="0" maxOccurs="unbounded" namespace="##any"`

*Struktuur kus viimane element on minOccurs="0" kordsusega ei ole XML Schema 1.0 nõuete alusel any deklaratsioon lubatud Unique Particle Attribution reegli tõttu. Vastavat reeglit on korrigeeritud XML Schema 1.1 versioonis.*

### Näide XML Schema

```xml
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://ametnik.smit/services" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified"
           xmlns:veeb="http://ametnik.smit/services" 
           xmlns:smit="http://ametnik.smit/smit">

<xs:annotation>
<xs:documentation xml:lang="et">
Näitedokumendi dokumentatsioon (seletav ja kirjeldav tekst)
</xs:documentation>
</xs:annotation>

<xs:complexType name="Ametijuhend">
<xs:sequence>
<xs:element name="isikukood" type="xs:string" />
<xs:element name="failiNimi" type="xs:string" />
<xs:element name="failiSuurus" type="xs:int" />
<xs:element name="failiLaiend" type="xs:string" />
<xs:element name="fail" type="xs:base64Binary" />
</xs:sequence>
</xs:complexType>

<xs:element name="AmetijuhendRequest">
<xs:annotation>
<xs:documentation xml:lang="et">
Ametijuhendi(te) pärimiseks vajaliku sõnumi element.
</xs:documentation>
<xs:appinfo>
<smit:queue>amr.ametijuhendRequest</smit:queue>
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="asutusId" type="xs:integer" />
<xs:element name="aktiivsedOnly" type="xs:boolean" />
<xs:element name="isikukood" type="xs:string" minOccurs="0" />
<xs:element name="yksusId" type="xs:integer" minOccurs="0" />
<xs:element name="muudetudAlates" type="xs:date" minOccurs="0" />
<xs:element name="muudetudKuni" type="xs:date" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="AmetijuhendResponse">
<xs:annotation>
<xs:documentation xml:lang="et">
Ametijuhendi(te) päringu vastusena tagstatav sõnumi element.
</xs:documentation>
<xs:appinfo>
<smit:queue>amr.ametijuhendResponse</smit:queue>
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Ametijuhend" type="veeb:Ametijuhend" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="AmetijuhendTopic">
<xs:annotation>
<xs:appinfo>
<smit:topic>amr.ametijuhendTopic</smit:topic>
</xs:appinfo>
<xs:documentation xml:lang="et">
Ametijuhendi(te) uuenemisel publitseeritava sõnumi sisu
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Ametijuhend" type="veeb:Ametijuhend" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="AmetijuhendQueue">
<xs:annotation>
<xs:appinfo>
<smit:queue>amr.ametijuhendQueue</smit:queue>
</xs:appinfo>
<xs:documentation xml:lang="et">
Ametijuhendi(te) uuenemisel publitseeritava sõnumi sisu
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Ametijuhend" type="veeb:Ametijuhend" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>

</xs:schema>
```

## SOAP teenuste tarbimise head tavad

- **Kaasaegsed SOAP teegid**: Kasutada kaasaegseid SOAP teeke nagu Apache CXF või Spring Web Services
- **"Contract-First" arendus**: WSDL lepingud tuleb defineerida enne implementatsiooni
- **Tüübiohutus**: Kasutada WSDL-ist genereeritud klasse tüübiohutuse tagamiseks
- **Veakäsitlus**: Implementeerida korrektne SOAP "fault" käsitlus
- **Turvalisus**: Kasutada WS-Security SOAP sõnumite turvalisuse tagamiseks vajadusel
- **Jõudlus**: Kaaluda SOAP sõnumite optimeerimist ja tihendamist
- **Testimine**: Kasutada SOAP UI või sarnaseid tööriistu SOAP teenuste testimiseks

## Kategooriate kokkuvõte

| Sektsioon | Kohustuslikud | Valikulised | Kokku |
|-----------|---------------|-------------|-------|
| **Sünkroonne ja asünkroonne suhtlusviis** | 0 | 0 | 0 |
| **Integratsioon süsteemide vahel** | 5 | 0 | 5 |
| **Sõnumivahetuse nõuded (MQ)** | 8 | 1 | 9 |
| **REST API ja HTTP/JSON API** | 12 | 3 | 15 |
| **SOAP teenuste arendamise nõuded** | 3 | 0 | 3 |
| **SOAP teenuste tarbimise head tavad** | 0 | 7 | 7 |
| **Kokku** | **28** | **11** | **39** |

## Märkused

- **KOHUSTUS** = Kohustuslik nõue
- **Soovituslik** = Soovitatud/valikuline nõue
- Integratsiooninõuded vajavad arhitektuurilisi otsuseid ja inimeste järelevalvet
- Protokollide valik sõltub konkreetsest kasutusjuhtumist ja olemasolevatest süsteemidest
- X-TEE integratsioonid nõuavad spetsiaalset dokumentatsiooni ja kooskõlastamist
- Sõnumivahetuse kanalite nimetused peavad olema kooskõlastatud SMIT-iga

---
